import idljGenerated.*;
import middleware.*;
import java.util.*;

public class ColaboradorReinas extends IColaboradorReinasPOA
        implements CallbackNuevaSolucion
{
    private String nombre;
    private Vector<TableroReinas> soluciones;
    private IColaboradorReinas colaboradorReinas;
    private PiscinaHilos piscina;

    private synchronized void anyadirSolucion(TableroReinas s)
    {
        soluciones.add(s);
    }

    public ColaboradorReinas(String nombre)
    {
        this.nombre = nombre;
        soluciones = new Vector<TableroReinas>();
        int n_procesadores = Runtime.getRuntime().availableProcessors();
        piscina = new PiscinaHilos(n_procesadores);
    }

    @Override
    public String nombre()
    {
        return nombre;
    }

    @Override
    public void evaluaSubArbol(int[] t, ISolucionesReinas jefe)
    {
        System.out.println("Colaborador " + nombre + " recibe trabajo");

        // Creamos una solucion parcial a partir del array recibido.
        TableroReinas tablero = new TableroReinas(t, true);

        // Desarrollamos la solucion parcial recibida dos niveles mas, (para
        // asegurarnos de tener soluciones parciales para todos los procesadores).
        // Las nuevas soluciones parciales resultantes se anyadiran como actividades 
        // a la piscina.
        AnalizaColumna.func(tablero.getColumnasCompletadas() + 2, tablero, this);

        // Esperamos a que se vacie la piscina.
        piscina.esperarOciosa();

        // Pasamos las soluciones a formato array.
        int[][] arraySoluciones = new int[soluciones.size()][t.length];
        for(int i = 0; i < soluciones.size(); i++)
            arraySoluciones[i] = soluciones.get(i).toArray();

        // Limpiamos las soluciones antes de enviarlas porque es tan
        // rapido que puede que nos envien mas trabajo antes de que de
        // tiempo a limpiarlo.
        soluciones.clear();

        // Enviamos las soluciones.
        System.out.println("Colaborador " + nombre + " envia soluciones");
        jefe.recibeSoluciones(arraySoluciones, colaboradorReinas);
    }

    public void tratarNuevaSolucion(TableroReinas solucion)
    {
        // Si es una solucion final, la guardamos.
        if (solucion.getColumnasCompletadas() == solucion.getTamanyo())
        {
            anyadirSolucion(solucion.clone());
            return;
        }

        //Si es una solucion parcial, creamos una actividad, y a la piscina.
        Actividad act = new Actividad(solucion.clone(), this);
        piscina.nuevaTarea(act);
    }

    public static void main(String[] args)
    {
        if (args.length < 1)
        {
            System.out.println("java ColaboradorReinas identificador");
            System.out.println("Siendo identificador de este colaborador.");
            return;
        }

        // Inicializar middleware:
        JavaORB mdlw = new JavaORB();
		mdlw.nombreSN = "pcdultimate";
		mdlw.opcionesLC = args;

        // A partir de aqui, codigo es independiente de middleware!
        Middleware.inicializar(mdlw);

        // Crear sirviente
        ColaboradorReinas sirviente = new ColaboradorReinas(args[0]);

        // Registrarse
        IColaboradorReinas colaboradorReinas =
            (IColaboradorReinas)Middleware.registrar(sirviente, "IColaboradorReinas");
        sirviente.colaboradorReinas = colaboradorReinas;

        // Localizar el directorio de colaboradores
        IDirectorioColaboradores directorioColaboradores =
            (IDirectorioColaboradores)Middleware.localizar(
                    "directorioColaboradores", "IDirectorioColaboradores");

        // Si no se pudo localizar
        if (directorioColaboradores == null)
        {
            System.out.println("No se encontro directorio de colaboradores en el que darse de alta.");
            return;
        }

        int error = directorioColaboradores.altaColaborador(colaboradorReinas);
        if(error == -1)
        {
            System.out.println("Ya existe un colaborador con el nombre indicado.");
            return;
        }
        System.out.println("Colaborador " +
                colaboradorReinas.nombre() +
                " dado de alta en el directorio de colaboradores.");

        // Manejador para darse de baja del directorio de colaboradores.
        ManejadorBajas sh = new
            ManejadorBajas(directorioColaboradores,colaboradorReinas);
        Runtime.getRuntime().addShutdownHook(sh);
        Middleware.esperar();
    }
    
    // Clase interna que implementa la interfaz Runnable para poder ser
    // procesada por la piscina de hilos.
    private class Actividad implements Runnable
    {
        private TableroReinas solucionParcial;
        private CallbackNuevaSolucion callback;

        public Actividad(TableroReinas solucionParcial, CallbackNuevaSolucion callback)
        {
            this.solucionParcial = solucionParcial;
            this.callback = callback;
        }

        public void run()
        {
            // Resuelve la solucion parcial hasta el final.
            AnalizaColumna.func(solucionParcial.getTamanyo(), solucionParcial, callback);
        }
    }
}